/**
 * 
 */
package com.zznode.client.wlanpolling.other;

import java.io.ByteArrayInputStream;
import java.util.Collections;
import java.util.List;
import java.util.SortedMap;

import javax.xml.xpath.XPathConstants;

import org.achartengine.GraphicalView;
import org.achartengine.chart.DialChart;
import org.achartengine.chart.PointStyle;
import org.achartengine.chart.TimeChart;
import org.achartengine.model.CategorySeries;
import org.achartengine.model.TimeSeries;
import org.achartengine.model.XYMultipleSeriesDataset;
import org.achartengine.renderer.DialRenderer;
import org.achartengine.renderer.DialRenderer.Type;
import org.achartengine.renderer.SimpleSeriesRenderer;
import org.achartengine.renderer.XYMultipleSeriesRenderer;
import org.achartengine.renderer.XYSeriesRenderer;
import org.w3c.dom.Node;

import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;

import com.zznode.client.wlanpolling.R;
import com.zznode.client.wlanpolling.WLANPollingApplication;
import com.zznode.client.wlanpolling.model.WLANPollManager;
import com.zznode.client.wlanpolling.model.WebSite;
import com.zznode.client.wlanpolling.model.WebSiteManager;
import com.zznode.client.wlanpolling.service.net.HttpCallback;
import com.zznode.client.wlanpolling.service.net.HttpException;
import com.zznode.client.wlanpolling.service.xml.XmlXPathAdaptor;
import com.zznode.client.wlanpolling.utils.ThroughtOuputputRatesExceuteListener;
import com.zznode.client.wlanpolling.utils.ThroughtOuputputRatesExceuteTask;
import com.zznode.client.wlanpolling.utils.PingUtils;

/**
 * @author Pink
 * 
 */
public class WebSpeedTestMainActivity extends Activity implements
		ThroughtOuputputRatesExceuteListener, HttpCallback {
	private WLANPollingApplication application;

	private double MIN = 0;
	private double MAX = 1024 * 10;// 10M

	private double R256 = 256;
	private double R512 = 512;
	private double R1024 = 1024;
	private double R3072 = 3072;
	private double R5120 = 5120;
	private double R10240 = 10240;

	protected Bitmap dashboard = null;
	protected Bitmap center = null;
	protected Bitmap pointer = null;

	protected GraphicalView dashboardChart;
	protected CategorySeries category = new CategorySeries("");
	protected DialRenderer dashboardRenderer = new DialRenderer();

	protected GraphicalView chartView;
	protected XYMultipleSeriesDataset dataset = new XYMultipleSeriesDataset();
	protected XYMultipleSeriesRenderer chartRenderer = new XYMultipleSeriesRenderer();

	private TextView tvNetType;
	private TextView tvSpeed;
	private TextView tvAvgSpeed;

	private int maxSpeed = 0;
	private int minSpeed = Integer.MAX_VALUE;
	private int avgSpeed = 0;
	private int speed = 0;

	protected boolean stopped = true;
	private WebSite webSite;

	private ThroughtOuputputRatesExceuteTask throughtOuputputRatesExceuteTask;
	private UpdateUIHandler updateUIHandler;

	private Button btnBeginTest;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		setContentView(R.layout.webspeedtestmain);

		application = (WLANPollingApplication) getApplication();
		initResource();

		bindView();
		bindEvent();

		initSpinner();
	}

	private void initResource() {
		dashboard = BitmapFactory.decodeResource(getResources(),
				R.drawable.pic_dashboard);
		center = BitmapFactory
				.decodeResource(getResources(), R.drawable.center);
		pointer = BitmapFactory.decodeResource(getResources(),
				R.drawable.pointer);
	}

	private void bindView() {
		tvNetType = (TextView) findViewById(R.id.tvNetType);
		tvSpeed = (TextView) findViewById(R.id.tvSpeed);
		tvAvgSpeed = (TextView) findViewById(R.id.tvAvgSpeed);

		initCharts();
	}

	private void bindEvent() {

		Looper looper = Looper.myLooper();
		updateUIHandler = new UpdateUIHandler(looper);

		btnBeginTest = (Button) findViewById(R.id.btnBeginTest);

		btnBeginTest.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				// 开始测试
				if (stopped == true) {
					startTest();
				} else {
					stopTest();
				}
			}
		});

		Button btnSelWebSite = (Button) findViewById(R.id.btnSelWebSite);
		btnSelWebSite.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				// 选择当前测试的网站
				Intent i = new Intent(WebSpeedTestMainActivity.this,
						WebSiteListActivity.class);
				WebSpeedTestMainActivity.this.startActivityForResult(i, 0);
			}
		});

		Button btnSaveResult = (Button) findViewById(R.id.btnSaveResult);
		btnSaveResult.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				if (stopped && webSite != null && speed > 0) {
					String apMac = PingUtils.clearMacAdress(application
							.getContext().getCurrentWifi().getBSSID());
					WLANPollManager.getWLANPollManager().postWebSiteResult(
							WebSpeedTestMainActivity.this, apMac,
							webSite.getName(), webSite.getUrl(), maxSpeed + "",
							avgSpeed + "", minSpeed + "");
				}
			}
		});
	}

	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		if (requestCode == 0) {
			// 设置选择的网站
			initSpinner();
			return;
		}
		super.onActivityResult(requestCode, resultCode, data);
	}

	private void initSpinner() {
		Spinner spinner = (Spinner) findViewById(R.id.webSiteSpinner);
		List<WebSite> websites = WebSiteManager.getWebSiteManager()
				.getAllWebSite();
		final ArrayAdapter<WebSite> adapter = new ArrayAdapter<WebSite>(this,
				android.R.layout.simple_spinner_item, websites);
		if (websites.size() > 0) {
			spinner.setSelection(0);
		}
		adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
		spinner.setAdapter(adapter);

		spinner.setOnItemSelectedListener(new Spinner.OnItemSelectedListener() {

			@Override
			public void onItemSelected(AdapterView<?> adapterView, View view,
					int position, long arg3) {
				webSite = adapter.getItem(position);
			}

			@Override
			public void onNothingSelected(AdapterView<?> arg0) {
			}
		});
	}

	private void startTest() {
		if (stopped == false) {
			Toast.makeText(this, "正在执行测试", Toast.LENGTH_LONG).show();
			return;
		}

		if (webSite == null) {
			Toast.makeText(this, "必须选择一个站点", Toast.LENGTH_LONG).show();
			return;
		}

		stopped = false;
		btnBeginTest.setText("停止测试");

		dataset.getSeriesAt(0).clear();
		dashboardChart.invalidate();
		chartView.invalidate();

		throughtOuputputRatesExceuteTask = new ThroughtOuputputRatesExceuteTask(
				webSite.getUrl(), this, "webtest");

		Thread testWorker = new Thread(throughtOuputputRatesExceuteTask);
		testWorker.start();
	}

	private void stopTest() {
		if (stopped) {
			return;
		}
		btnBeginTest.setText("开始测试");
		throughtOuputputRatesExceuteTask.setInterrupted(true);
		throughtOuputputRatesExceuteTask = null;
		stopped = true;
	}

	protected void initCharts() {
		initDashboardRenderer();
		initChartRenderer();

		DialChart _chart = new DialChart(category, dashboardRenderer) {
			private static final long serialVersionUID = 7918317351060449803L;

			@Override
			public void draw(Canvas canvas, int x, int y, int width,
					int height, Paint paint) {
				canvas.drawBitmap(dashboard, x + 65, y, paint);
				super.draw(canvas, x, y, width, height, paint);
			}

			@Override
			protected void drawTicks(Canvas canvas, double min, double max,
					double minAngle, double maxAngle, int centerX, int centerY,
					double longRadius, double shortRadius, double ticks,
					Paint paint, boolean labels) {
			}

			@Override
			protected void drawNeedle(Canvas canvas, double angle, int centerX,
					int centerY, double radius, boolean arrow, Paint paint) {
				centerY += 10;
				canvas.save();
				canvas.translate(0, centerY);
				double realAngle = 360 * angle / Math.toRadians(360);
				canvas.rotate((float) (90 - 180 - realAngle), centerX, 0);
				canvas.drawBitmap(pointer, pointer.getWidth(),
						0 - pointer.getHeight() / 2, paint);
				canvas.restore();
				canvas.drawBitmap(center, centerX - center.getWidth() / 2,
						centerY - center.getHeight() / 2, paint);
			}

		};

		dashboardChart = (GraphicalView) this.findViewById(R.id.gvDashboard);
		dashboardChart.initChart(_chart);
		category.add("", 0);

		TimeSeries series = new TimeSeries("Speed") {
			private static final long serialVersionUID = 6020011893519305343L;

			@Override
			public synchronized SortedMap<Double, Double> getRange(
					double start, double stop, int beforeAfterPoints) {
				SortedMap<Double, Double> map = super.getRange(start, stop,
						beforeAfterPoints);
				return Collections.unmodifiableSortedMap(map);
			}

		};
		dataset.addSeries(series);
		TimeChart chart = new TimeChart(dataset, chartRenderer);
		chart.setDateFormat("");

		chartView = (GraphicalView) this.findViewById(R.id.gvChartview);
		chartView.initChart(chart);
	}

	protected void initDashboardRenderer() {
		dashboardRenderer.setShowLegend(false);
		dashboardRenderer.setShowLabels(false);
		SimpleSeriesRenderer r = new SimpleSeriesRenderer();
		r.setColor(Color.RED);
		dashboardRenderer.addSeriesRenderer(r);
		dashboardRenderer
				.setVisualTypes(new DialRenderer.Type[] { Type.ARROW });
		dashboardRenderer.setMinValue(MIN);
		dashboardRenderer.setAngleMin(285);
		dashboardRenderer.setMaxValue(MAX);
		dashboardRenderer.setAngleMax(75);
		dashboardRenderer.setPanEnabled(false);
		dashboardRenderer.setZoomEnabled(false);
	}

	protected void initChartRenderer() {
		chartRenderer = new XYMultipleSeriesRenderer();
		chartRenderer.setBackgroundColor(Color.DKGRAY);
		chartRenderer.setApplyBackgroundColor(true);
		chartRenderer.setInScroll(true);
		chartRenderer.setClickEnabled(false);
		chartRenderer.setXTitle("时间");
		chartRenderer.setYTitle("速率(KB/s)");
		chartRenderer.setLabelsColor(Color.WHITE);

		XYSeriesRenderer r = new XYSeriesRenderer();
		r.setColor(Color.GREEN);
		r.setLineWidth(2);
		r.setPointStyle(PointStyle.POINT);
		chartRenderer.addSeriesRenderer(r);

		chartRenderer.setMargins(new int[] { 20, 40, 10, 10 });
		chartRenderer.setMarginsColor(Color.DKGRAY);
		chartRenderer.setShowGrid(true);
		chartRenderer.setXAxisMax(200);
		chartRenderer.setXAxisMin(0);

		chartRenderer.setShowAxes(true);
		chartRenderer.setYAxisMax(1024);
		chartRenderer.setYAxisMin(0);
		chartRenderer.setPanEnabled(true, false);
		chartRenderer.setZoomEnabled(false);
		chartRenderer.setShowLabels(true);
		chartRenderer.setShowLegend(false);
		chartRenderer.setGridColor(Color.DKGRAY);

		chartRenderer.setYLabelsAlign(Align.RIGHT);
	}

	protected double dashboardValue(double realValue) {
		double startV = 0;
		double startR = 0;
		double ratio = 1;
		double diffV = 0;
		double diffR = 0;
		if (realValue > 0 && realValue <= R256) {
			startV = 0;
			startR = 0;
			diffR = 1536;
			diffV = R256;
		}
		if (realValue > R256 && realValue <= R512) {
			startV = R256;
			startR = 1536;
			diffR = 3584 - startR;
			diffV = R256;
		}
		if (realValue > R512 && realValue <= R1024) {
			startV = R512;
			startR = 3584;
			diffR = 5620 - startR;
			diffV = R512;
		}
		if (realValue > R1024 && realValue <= R3072) {
			startV = R1024;
			startR = 5620;
			diffR = 7168 - startR;
			diffV = 2048.0;
		}
		if (realValue > R3072 && realValue <= R5120) {
			startV = R3072;
			startR = 7168;
			diffR = 8704 - startR;
			diffV = 2048.0;
		}
		if (realValue > R5120 && realValue <= R10240) {
			startV = R5120;
			startR = 8704;
			diffR = R10240 - startR;
			diffV = R5120;
		}
		ratio = (realValue - startV) / diffV;
		return startR + ratio * diffR;
	}

	// marks for ThroughtOuputputRatesExceuteListener
	@Override
	public void onProgress(String tag, int downloadedSize, int time, int[] speeds) {
		// 计算速度
		Message msg = new Message();
		msg.obj = new int[] { time, speeds[0] };
		this.speed = speeds[0];
		this.avgSpeed = downloadedSize / time;
		
		if(speeds[0] > maxSpeed) {
			maxSpeed = speeds[0];
		}
		
		if(speeds[0] < minSpeed) {
			minSpeed = speeds[0];
		}
		
		updateUIHandler.sendMessage(msg);
	}

	@Override
	public void onExecuteOver(String tag, int downloadedSize, int totalTime,
			int averageSpeed, final Throwable exp) {
		if (exp != null) {
			runOnUiThread(new Runnable() {
				@Override
				public void run() {
					Toast.makeText(WebSpeedTestMainActivity.this, "测试失败,服务器返回:" + exp.getMessage(),
							Toast.LENGTH_SHORT).show();					
				}
			});
		} else {
			runOnUiThread(new Runnable() {
				@Override
				public void run() {
					Toast.makeText(WebSpeedTestMainActivity.this, "测试完毕,请保存结果!",
							Toast.LENGTH_SHORT).show();					
				}
			});
		}

		runOnUiThread(new Runnable() {
			@Override
			public void run() {
				stopTest();
			}
		});
	}

	@Override
	public void onReceiveData(byte[] data, final HttpException exp, int tag) {
		if (exp != null) {
			runOnUiThread(new Runnable() {
				@Override
				public void run() {
					Toast.makeText(getApplicationContext(), exp.getMessage(),
							Toast.LENGTH_LONG).show();
				}
			});
			return;
		}

		try {
			XmlXPathAdaptor xpathAdaptor = new XmlXPathAdaptor(
					new ByteArrayInputStream(data));

			Node resultCode = (Node) xpathAdaptor.evaluate("/NODE/RESULT_CODE",
					XPathConstants.NODE);
			String status = resultCode.getAttributes().getNamedItem("name")
					.getNodeValue();
			if (status != null && "1".equals(status)) {
				runOnUiThread(new Runnable() {
					public void run() {
						Toast.makeText(WebSpeedTestMainActivity.this,
								"测试结果提交成功!", Toast.LENGTH_LONG).show();
					}
				});
			} else {
				String value = resultCode.getTextContent();
				throw new Exception("设备测试结果提交失败!原因:" + value);
			}
		} catch (final Exception e) {
			runOnUiThread(new Runnable() {
				public void run() {
					Toast.makeText(WebSpeedTestMainActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show();
				}
			});
		}
	}

	class UpdateUIHandler extends Handler {

		public UpdateUIHandler(Looper looper) {
			super(looper);
		}

		@Override
		public void handleMessage(Message msg) {
			tvSpeed.setText(WebSpeedTestMainActivity.this.speed / 1204 + "KB/s");
			tvAvgSpeed.setText(WebSpeedTestMainActivity.this.avgSpeed / 1024
					+ "KB/s");
			int[] params = (int[]) msg.obj;
			category.add("", dashboardValue(params[1]));
			dataset.getSeriesAt(0).add(params[0], params[1] / 1024);

			dashboardChart.invalidate();
			chartView.invalidate();
		}
	}
}
